package ao.ai.ml.algo.supervised.regression.benchmark;

import ao.ai.ml.algo.supervised.model.example.ext.RegressionExample;
import ao.ai.ml.algo.supervised.model.example.impl.RegressionExampleImpl;
import ao.ai.ml.algo.supervised.model.validation.ext.NumericValidation;
import ao.ai.ml.algo.supervised.model.validation.impl.RandomNumericValidation;
import ao.ai.ml.algo.supervised.regression.linear.non_parametric.LocallyWeightedRegression;
import ao.ai.ml.algo.supervised.regression.linear.parametric.BatchGradientDescent;
import ao.ai.ml.algo.supervised.regression.linear.parametric.NormalEquationSolver;
import ao.ai.ml.algo.supervised.regression.linear.parametric.StochasticGradientDescent;
import ao.ai.ml.algo.supervised.regression.model.RegressionLearner;
import ao.ai.ml.model.feature_set.ext.num.NumericalFeatureList;
import ao.ai.ml.model.feature_set.impl.FeatureScalar;
import ao.ai.ml.model.feature_type.FeatureType;
import ao.ai.ml.model.feature_type.ext.MutableFeatureSet;
import ao.ai.ml.model.feature_type.impl.FeatureTypeImpl;
import ao.ai.ml.model.feature_type.impl.FeatureTypeSetImpl;
import ao.ai.ml.model.fitness.FitnessMeasure;
import ao.util.math.rand.Rand;
import ao.util.time.Stopwatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;

/**
 * User: aostrovsky
 * Date: 31-Jan-2010
 * Time: 9:33:51 AM
 */
public class SyntheticBenchmark
{
    //--------------------------------------------------------------------
	private static final Logger LOG =
        LoggerFactory.getLogger(
        		SyntheticBenchmark.class);


	//--------------------------------------------------------------------
	public static void main(String[] args)
	{
		Rand.randomize();

        List<RegressionExample> examples =
                randomDataSet(1000, 1.0);

        LOG.info("benchmarking {} examples", examples.size());
        benchmark(examples, new LocallyWeightedRegression());
        benchmark(examples, new NormalEquationSolver());
        benchmark(examples, new StochasticGradientDescent());
        benchmark(examples, new BatchGradientDescent());
	}


	//--------------------------------------------------------------------
	public static void benchmark(
			List<RegressionExample> data,
			RegressionLearner learner)
	{
		Stopwatch leanTimer = new Stopwatch();
        NumericValidation<NumericalFeatureList> numValid =
                new RandomNumericValidation<NumericalFeatureList>(
                        10, 0.1);
        FitnessMeasure fitness = numValid.validate(learner, data);

		LOG.info("{} has fitness {}, took {} ", new Object[]{
                    learner, fitness, leanTimer});
	}


	//--------------------------------------------------------------------
	private static List<RegressionExample> randomDataSet(
			int size, /*RealFunction f, */double noiseFactor)
	{
		LOG.info("generating data {}", size);

        FeatureType inputType  = new FeatureTypeImpl("x");
        FeatureType outputType = new FeatureTypeImpl("y");

        MutableFeatureSet inputFeatureTypes =
                new FeatureTypeSetImpl();
        inputFeatureTypes.add(inputType);

		List<RegressionExample> data =
                new ArrayList<RegressionExample>();

        double coefficient = Rand.nextDouble(-10, 10);
        double bias        = Rand.nextDouble(-10, 10);

		for (int i = 0; i < size; i++)
        {
            double x     = Rand.nextDouble(-10, 10);
            double noise = (Rand.nextDouble() - 0.5) * noiseFactor;
            double y     = coefficient * x + bias + noise;

            data.add(new RegressionExampleImpl(
                    new FeatureScalar(x, inputType),
                    new FeatureScalar(y, outputType)
            ));

//			data.add(randomExample(f, noise));
		}
		return data;
	}


//	//--------------------------------------------------------------------
//	private static Example randomExample(
//			RealFunction f, double noise) {
//		return PurturbedExample.purturb(
//					KernelTrick.addQuadratic(
////					KernelTrick.addSine(
//							RealFunction.Impl.newExample(f)),
//					noise);
//	}
}
